// 标签名 a-aaa
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`;
// 命名空间标签 aa:aa-xxx
const qnameCapture = `((?:${ncname}\\:)?${ncname})`;
// 开始标签
const startTagOpen = new RegExp(`^<${qnameCapture}`); // 标签开头的正则 捕获的内容是标签名
// 结束标签
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`); // 匹配标签结尾的 </div>
// 匹配属性
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
// 匹配标签结束的 >
const startTagClose = /^\s*(\/?)>/;

export function parseHTML(html) {
  const ELEMENT_TYPE = 1;
  const TEXT_TYPE = 3;
  const stack = []; // 栈
  let currentParent; // 指针，指向栈的最后一个
  let root; // ast 语法树的根节点

  function createASTElement(tag, attrs) {
    return {
      tag,
      attrs,
      children: [],
      type: ELEMENT_TYPE,
      parent: null,
    };
  }

  function start(tagName, attrs) {
    let node = createASTElement(tagName, attrs);
    if (!root) {
      root = node;
    }
    if (currentParent) {
      node.parent = currentParent;
      currentParent.children.push(node);
    }
    stack.push(node);
    currentParent = node;
  }

  function chars(text) {
    text = text.replace(/\s/g, '');
    if (text) {
      currentParent.children.push({
        type: TEXT_TYPE,
        text,
        parent:currentParent
      });
    }
  }

  function end(tagName) {
    stack.pop();
    currentParent = stack[stack.length - 1];
  }

  function advance(n) {
    html = html.substring(n);
  }

  while (html) {
    // html 为空时结束
    let textEnd = html.indexOf('<');
    if (textEnd == 0) {
      // 为标签
      const startTagMatch = parseStartTag();

      if (startTagMatch) {
        start(startTagMatch.tagName, startTagMatch.attrs);
        continue;
      }

      const endTagMatch = html.match(endTag);
      if (endTagMatch) {
        advance(endTagMatch[0].length);
        end(endTagMatch[1]);
        continue;
      }
    }
    let text;
    if (textEnd > 0) {
      text = html.substring(0, textEnd);
    }
    if (text) {
      advance(text.length);
      chars(text);
    }
  }

  function parseStartTag() {
    const start = html.match(startTagOpen);
    if (!start) {
      return false;
    }
    let match = {
      tagName: start[1],
      attrs: [],
    };
    // 删除开始标签字符串
    advance(start[0].length);
    // 处理属性
    let attr;
    let end;

    while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
      match.attrs.push({ name: attr[1], value: attr[3] || attr[4] || attr[5] });
      advance(attr[0].length);
    }

    if (end) {
      advance(end[0].length);
    }
    return match;
  }

  return root;
}
